package com.itheima.health.aspect;

import com.itheima.health.annotation.AutoFill;
import com.itheima.health.common.AutoFillConstant;
import com.itheima.health.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

@Component
@Aspect
@Slf4j
public class AutoFillAspect {
    //定义一个切点，表示哪些方法会被通知
    @Pointcut("execution(* com.itheima.health.mapper.*.*(..)) && @annotation(com.itheima.health.annotation.AutoFill)")
    public void autoFillPointcut(){};

    @Before("autoFillPointcut()")
    public void autoFill(JoinPoint joinPoint) throws NoSuchMethodException {
        //获取被通知的方法集合
        Object[] args = joinPoint.getArgs();
        if(CollectionUtils.isEmpty(Arrays.asList(args))){
            return;
        }

        log.info("开始进行公共字段填充");

        //用于获取连接点的签名(包含了方法的基本信息)
        MethodSignature signature=(MethodSignature) joinPoint.getSignature();
        //通过前面得到切入的方法，然后再得到方法上指定的注解AutoFill
        AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);
        //得到获取到的指定AutoFill注解上的操作类型insert或update
        OperationType operationType=annotation.value();

        //取方法集合中的第一个
        Object entity=args[0];

        //插入对应字段补充基础属性

        try {
            if(operationType == OperationType.INSERT){
                //通过反射获取类的class对象，然后获的对象中的方法，以及想要获取的方法名称：AutoFillConstant.SET_CREATE_TIME=setCreateTime
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);

                //将调用entity上的setCreateTime方法，并将当前日期时间作为参数传递
                setCreateTime.invoke(entity,LocalDateTime.now());
                setUpdateTime.invoke(entity,LocalDateTime.now());
            }

            if(operationType==OperationType.UPDATE){
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);

                setUpdateTime.invoke(entity,LocalDateTime.now());
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}
